package com.vmj.rtda;

import com.vmj.common.BytesReader;
import com.vmj.instructions.Interpreter;
import com.vmj.instructions.base.Instruction;

import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by yangshoujun on 2017/8/12 上午11:50.
 */
public class Thread {

    int pc;
    Stack stack;
    private List<Frame> frames = new ArrayList<Frame>();

    public void loop(byte[] byteCode) {

        Frame frame = this.getCurrentFrame();
        BytesReader reader = new BytesReader(byteCode, ByteOrder.BIG_ENDIAN);
        while(true) {
            int pc = frame.getNextPc();
            this.setPc(pc);
            reader.reset(byteCode, pc);
            int opCode = reader.readByte();
            opCode &= 0xFF;
            Instruction instruction = Interpreter.getInstruction(opCode);
            instruction.fetchOperands(reader);
            frame.setNextPc(reader.getOffset());
            instruction.execute(frame);
            if(this.isStackEmpty()) {
                break;
            }
        }
    }

    public Thread() {
        stack = new Stack(1024);
    }

    public int getPc() {
        return pc;
    }

    public Stack getStack() {
        return stack;
    }

    public void setPc(int pc) {
        this.pc = pc;
    }

    public void setStack(Stack stack) {
        this.stack = stack;
    }

    public void pushFrame(Frame frame) {
        stack.pushFrame(frame);
        frames.add(frame);
    }

    public Frame popFrame() {
        frames = frames.subList(0, frames.size()-1);
        return stack.popFrame();
    }

    public Frame getCurrentFrame() {
        return stack.currentFrame();
    }

    public Frame[] getFrames() {
        Frame[] frames = new Frame[this.frames.size()];
        this.frames.toArray(frames);
        return frames;
    }

    public boolean isStackEmpty() {
        return stack.isEmpty();
    }

    public void clearStack() {
        while (!isStackEmpty()) {
            stack.popFrame();
        }
    }
}
